#include "ActionPurchaseReq.h"
#include "json.h"
#include "util.h"
#include "streamdata.h"
#include "agencyevent.h"
#include "agencyeventmgr.h"
#include "agency_event_service.h"
#include "flow_service.h"
#include "api_order_service.h"
#include "9200_agency_event_api.pb.h"
#include "3400_api_order.pb.h"


static std::map<std::string,std::string> http_json_heads = {{"Content-Type","application/json"}};

static bool __init__ = ActionPurchaseReq::Init();

bool ActionPurchaseReq::Init()
{
    Ctx.msg_router.BindMsg(agency_event_api::AGENCY_EVENT_API_MSGID_PURCHASE_REQ, ActionPurchaseReq::HandlePurchaseReq);
    AgencyEventService::Instance()->ListenOnAgencyEventGet(AgencyEventService::PURCHASE, ActionPurchaseReq::OnAgencyGet);

    return true;
}

void ActionPurchaseReq::HandlePurchaseReq(MsgData&& msg_data)
{
    agency_event_api::PurchaseReq req;
    agency_event_api::PurchaseResp resp;

    do
    {
        if (!req.ParseFromArray(msg_data.data.data(), msg_data.data.size()))
        {
            resp.set_errorcode(agency_event_api::ErrorCode::DataParseErr);
            log_error("parser msg failed uuid=%u", msg_data.uuid);
            break;
        }

        {
            auto* order_info = req.mutable_order_info();
            if (req.order_info().fee() < 0) order_info->set_fee(-req.order_info().fee());
        }

        log_debug("req:%s", req.ShortDebugString().c_str());
        
        stAgencyEvent* agency = AgencyEventMgr::Instance()->Get(req.agency_id());
        if (agency != nullptr)
        {
            PurchaseOrderInfo order_info;
            order_info.purchase_time = req.order_info().purchase_time();
            order_info.order_id = req.order_info().order_id();
            order_info.fee = req.order_info().fee();
            order_info.cycle = req.order_info().cycle();
            
            PurchaseRegParam p;
            p.user_id = req.uid();
            p.username = req.username();
            p.agency_id = req.agency_id();
            p.game_id = req.game();
            p.balance = req.balance();
            p.order_info = order_info;
            p.scene_from = req.scene_from();

            p.agency_name = agency->agency_name;
            p.currency = agency->currency;
            p.currency_unit_multi = agency->currency_unit_multi;
            
            // 发起请求
            Request(agency->call_url, req.trans(), 
                req.uid(), msg_data.svtype, msg_data.svid, msg_data.uuid, p);
        }
        else
        {
            // 获取代理商信息
            StreamData stream_data;
            StreamDataWriter writer(stream_data);
            writer.WriteInt(req.uid());
            writer.WriteString(req.username());
            writer.WriteInt(req.agency_id());
            writer.WriteInt(req.game());
            writer.WriteInt64(req.balance());
            writer.WriteInt64(req.order_info().purchase_time());
            writer.WriteInt64(req.order_info().order_id());
            writer.WriteInt64(req.order_info().fee());
            writer.WriteInt64(req.order_info().cycle());
            writer.WriteInt(req.scene_from());

            writer.WriteString(req.trans());
            writer.WriteShort(msg_data.svtype);
            writer.WriteInt(msg_data.svid);
            writer.WriteInt(msg_data.uuid);
            
            if (!AgencyEventService::Instance()->HandleGetAgencyEvent(req.agency_id(), std::move(stream_data.Data()), AgencyEventService::PURCHASE))
            {
                resp.set_errorcode(agency_event_api::ErrorCode::AgentGetErr);
                log_error("HandleGetAgencyEvent parser msg failed");
                break;
            }
        }
        return;
    } while (false);
    
    if (resp.errorcode() != 0)
    {
        // 回包
        resp.set_message(ToString(resp.errorcode()));
        resp.set_uid(req.uid());
        resp.set_trans(req.trans());
        Ctx.host->MtSendtoOneSrv(agency_event_api::AGENCY_EVENT_API_MSGID_PURCHASE_RESP, &resp, msg_data.svtype, msg_data.svid, false, msg_data.uuid);
    }
}

void ActionPurchaseReq::OnAgencyGet(std::int32_t err_code, stAgencyEvent* agency, std::string&& trans)
{
    PurchaseRegParam p;

    StreamData stream_data(std::move(trans));
    StreamDataReader reader(stream_data);
    p.user_id = reader.ReadInt();
    p.username = reader.ReadString();
    p.agency_id = reader.ReadInt();
    p.game_id = reader.ReadInt();
    p.balance = reader.ReadInt64();
    p.order_info.purchase_time = reader.ReadInt64();
    p.order_info.order_id = reader.ReadInt64();
    p.order_info.fee = reader.ReadInt64();
    p.order_info.cycle = reader.ReadInt64();
    p.scene_from = reader.ReadInt();
    
    std::string req_trans = reader.ReadString();
    std::uint16_t svtype = reader.ReadShort();
    std::uint32_t svid = reader.ReadInt();
    std::uint32_t uuid = reader.ReadInt();

    agency_event_api::PurchaseResp resp;
    do
    {
        if (err_code != 0)
        {
            resp.set_errorcode(agency_event_api::ErrorCode::AgencyGetErr);
            log_error("get agencyevent info failed, uid:%u, agency_id=%u, err_code:%d;", p.user_id, p.agency_id, err_code);
            break;
        }
        if (agency == nullptr)
        {
            resp.set_errorcode(agency_event_api::ErrorCode::AgencyGetErr);
            log_error("agencyevent is nullptr, uid:%u, agency_id=%u, err_code:%d;", p.user_id, p.agency_id, err_code);
            break;
        }
		log_debug("agency:%s;", agency->ToString().c_str());

        p.agency_name = agency->agency_name;
        p.currency = agency->currency;
        p.currency_unit_multi = agency->currency_unit_multi;

        Request(agency->call_url, req_trans, p.user_id, svtype, svid, uuid, p);
    } while (false);
    
    if (resp.errorcode() != 0)
    {
        // 失败立即回包
        resp.set_message(ToString(resp.errorcode()));
        resp.set_uid(p.user_id);
        resp.set_trans(std::move(req_trans));
        Ctx.host->MtSendtoOneSrv(agency_event_api::AGENCY_EVENT_API_MSGID_PURCHASE_RESP, &resp, svtype, svid, false, uuid);
    }
}

void ActionPurchaseReq::Request(
    const std::string& baseurl, const std::string& trans,
    std::uint32_t uid, std::uint16_t svtype, std::uint32_t svid,
    std::uint32_t uuid, const PurchaseRegParam& params)
{
    agency_event_api::PurchaseResp resp;

    do
    {
        if (params.currency_unit_multi == 0)
        {
            resp.set_errorcode(agency_event_api::ErrorCode::AbnormalErr);
            log_error("currency_unit_multi is 0, uid:%u, agency_id=%u, cycle:%lu, order_id:%lu, currency:%s;"
                ,uid, params.agency_id, params.order_info.cycle, params.order_info.order_id, params.currency.c_str());
            break;
        }

        std::string req_id = GenTransId();
        std::uint64_t now = CTools::GetUnixTime();

        Json::Value http_req;
        http_req["reqId"] = req_id;
        http_req["username"] = params.username;
        http_req["currency"] = params.currency;
        http_req["game"] = params.game_id;
        http_req["round"] = Json::UInt64(params.order_info.order_id);// 
        http_req["purchtime"] = Json::UInt64(params.order_info.purchase_time);
        http_req["price"] = Json::Int64(params.order_info.fee * 1.0 / params.currency_unit_multi);
        http_req["cycle"] = Json::UInt64(params.order_info.cycle);

        std::string json_string = CTools::ToStr(http_req);
        std::string url = baseurl + "/purchase";

        api_order::ApiOrder api_order;
        api_order.set_uid(uid);
        api_order.set_op(api_order::API_ORDER_OP_PURCHASE);
        api_order.set_username(params.username);
        api_order.set_agency(params.agency_name);
        api_order.set_currency(params.currency);
        api_order.set_gameid(params.game_id);
        api_order.set_url(url);
        api_order.set_req_id(req_id);
        api_order.set_req_body(json_string);
        api_order.set_start_time(now);
        api_order.set_update_time(now);
        api_order.set_cycle(params.order_info.cycle);
        api_order.set_orderid(params.order_info.order_id);
        api_order.set_bet(params.order_info.fee);
        api_order.set_balance(params.balance);
        api_order.set_scene_from(params.scene_from);
        api_order.set_stype_from(svtype);
        api_order.set_svid_from(svid);

        std::uint32_t event_id = 0;
        // 请求http网络
        if (!Ctx.msg_router.sendHttpPOST(url, json_string, http_json_heads, event_id) || (event_id == 0))
        {
            resp.set_errorcode(agency_event_api::ErrorCode::SendPostErr);
            log_error("net post failed, url:%s, param:%s;", url.c_str(), json_string.c_str());
            break;
        }
        log_debug("http post, url:%s, param:%s;", url.c_str(), json_string.c_str());
        
        // 添加回调监听
        Ctx.msg_router.AddCurlEvent(event_id, [uid, svtype, svid, uuid, req_trans=std::move(trans), params = params,
            url=std::move(url), json_string= std::move(json_string), api_order_v = std::move(api_order)](std::string& body, bool is_ok){
            
            agency_event_api::PurchaseResp resp;
            Json::Value http_resp;
            
            std::uint64_t now = CTools::GetUnixTime();
            api_order::ApiOrder api_order = std::move(api_order_v);
            api_order.set_update_time(now);
            api_order.set_resp_body(body);
            do
            {
                if (!is_ok)
                {
                    resp.set_errorcode(agency_event_api::ErrorCode::RespTimeout);
                    log_error("time out, url:%s, param:%s;", url.c_str(), json_string.c_str());
                    break;
                }
                
                // 解析返回格式
                if (!CTools::FromStr(http_resp, body))
                {
                    resp.set_errorcode(agency_event_api::ErrorCode::DataParseErr);
                    log_error("resp from json failed, body:%s, url:%s, param:%s;", body.c_str(), url.c_str(), json_string.c_str());
                    break;
                }

                if (!http_resp.isMember("username") || !http_resp["username"].isString()
                    || !http_resp.isMember("currency") || !http_resp["currency"].isString() 
                    || !http_resp.isMember("balance") || !http_resp["balance"].isDouble()
                    || !http_resp.isMember("errorCode") || !http_resp["errorCode"].isInt()
                    || !http_resp.isMember("message") || !http_resp["message"].isString()
                )
                {
                    resp.set_errorcode(agency_event_api::ErrorCode::InvaildParam);
                    log_error("response param invalid, body:%s, url:%s, param:%s;", body.c_str(), url.c_str(), json_string.c_str());
                    break;
                }
            
                if (params.currency_unit_multi == 0)
                {
                    resp.set_errorcode(agency_event_api::ErrorCode::AbnormalErr);
                    log_error("currency_unit_multi is 0, body:%s, url:%s, param:%s;", body.c_str(), url.c_str(), json_string.c_str());
                    break;
                }

                resp.set_errorcode(http_resp["errorCode"].asInt());
                resp.set_balance(http_resp["balance"].asDouble() * params.currency_unit_multi);
                
                std::int64_t txid = 0;
                if (http_resp.isMember("txId") && http_resp["txId"].isInt64()) 
                {
                    txid = http_resp["txId"].asInt64();
                }
                api_order.set_resp_id(txid);
                api_order.set_balance(resp.balance());
            } while (false);
            
            // 回包
            resp.set_message(ToString(resp.
                errorcode()));
            resp.set_uid(uid);
            resp.set_trans(std::move(req_trans));
            log_debug("resp:%s;", resp.ShortDebugString().c_str());

            Ctx.host->MtSendtoOneSrv(agency_event_api::AGENCY_EVENT_API_MSGID_PURCHASE_RESP, &resp, svtype, svid, false, uuid);

            // 记流水表
            if (api_order.scene_from() == 0)
            {   
                FlowService::Instance()->OnPurchaseReg(
                    resp.errorcode(), resp.balance(), GameProvider(), 
                    params.user_id, params.agency_id, params.game_id, params.order_info.cycle, 
                    params.order_info.order_id, api_order.start_time(), params.order_info.fee, params.order_info.purchase_time
                );
            }

            // 购买超时和失败 记异常表
            api_order.set_err_code(resp.errorcode());
            ApiOrderService::Instance()->OnApiOrderUpdate(api_order);
        });
        return;

    } while (false);

    if (resp.errorcode() != 0)
    {
        // 失败回包
        resp.set_message(ToString(resp.errorcode()));
        resp.set_uid(uid);
        resp.set_trans(std::move(trans));
        Ctx.host->MtSendtoOneSrv(agency_event_api::AGENCY_EVENT_API_MSGID_PURCHASE_RESP, &resp, svtype, svid, false, uuid);
    }
}


